package cn.fulong.frame.service;

import cn.fulong.frame.config.Platform;
import cn.fulong.frame.consts.Constant;
import cn.fulong.frame.view.Pagination;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.MethodUtils;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
public abstract class GetData {
    @Autowired
    private JdbcTemplate jdbcTemplate;

    public Map execute(Map dataset, Map args) throws Exception {
        return null;
    }

    public String getStringFromDataset(Map dataset, String arg) {
        Object obj = dataset.get(arg);
        if (obj == null) {
            log.info("缺少参数：" + arg);
            return null;
        }
        return obj.toString();
    }

    /**
     * 拼装SQL
     *
     * @param sql     String ="select ... from table order by ${1} desc"
     * @param dataset sqlparts Map = { key=”${1}”, value=”arg3” }<br/>
     *                option Map = {1,col1; 2,col2}
     * @param args    Map = { key=arg3,value=”1” }
     * @return "select ... from table order by col1 desc"
     */
    protected String assemble(String sql, Map dataset, Map args) {
        Map sqlparts = getSqlparts(dataset);
        if (sqlparts == null || sqlparts.size() < 1) {
            return sql;
        }
        Pattern p = Pattern.compile("\\$\\{\\d+\\}");
        Matcher m = p.matcher(sql);
        while (m.find()) {
            // 找到需替换部分${1}
            String findStr = m.group();
            // 找到参数 ${1}定义
            Map sqlpart = (Map) sqlparts.get(findStr);
            String argument = (String) args.get(sqlpart.get("arg"));

            String replace = "";
            int type = (sqlpart.get("type") == null) ? 1 : (Integer) sqlpart.get("type");
            if (type == 2) {
                // 多项选择情况
                if (StringUtils.isBlank(argument)) {
                    // 没有客户端参数,使用默认参数
                    replace = (String) sqlpart.get("");
                } else {
                    // 根据客户参数查找对应的配置值
                    replace = (String) sqlpart.get(argument);
                    if (StringUtils.isBlank(replace)) {
                        replace = (String) sqlpart.get("defaultValue");
                    }
                }
            } else if (type == 3) {
                // sql语句从DB读取，多行拼接
                String sqlInParts = (String) sqlpart.get("sql");
                List<Map<String, Object>> list = jdbcTemplate.queryForList(sqlInParts, new Object[]{argument});
                StringBuffer s = new StringBuffer();
                for (Map<String, Object> record : list) {
                    for (Map.Entry entry : record.entrySet()) {
                        s.append(entry.getValue());
                        break;
                    }
                    s.append(",");
                }
                replace = s.substring(0, s.length() - 1);
            } else {
                // 空和非空情况
                if (StringUtils.isBlank(argument)) {
                    replace = (String) sqlpart.get("null");
                } else {
                    replace = (String) sqlpart.get("notNull");
                    if ("arg".equals(replace)) {
                        // 2021.9.30修改为仅支持order
                        replace = dealOrder(argument);
                        // 此种情况有sql注入隐患，只能给其他程序调用，不提供给前端
//                        if (AntiSQLInjectionUtil.isIllegal(argument)) {
//                            replace = "";
//                        } else {
//                            replace = argument;
//                        }
                    } else if ("arg,".equals(replace)) {
                        replace = dealOrder(argument);
                        if (!"".equals(replace)) {
                            replace = replace + ",";
                        }
//                        if (AntiSQLInjectionUtil.isIllegal(argument)) {
//                            replace = "";
//                        } else {
//                            replace = argument + ",";
//                        }
                    }
                }
            }

            if (replace == null) {
                replace = "";
            }
            sql = sql.replace(findStr, replace);
        }
        return sql;
    }

    private String dealOrder(String arg) {
        //必须用$连接
        String[] s = arg.split("$");
        if (s.length != 2) {
            return "";
        }
        //必须是1 asc或2 desc
        if (!"1".equals(s[1]) && !"2".equals(s[1])) {
            return "";
        }
        //不能有特殊字符
        if (!Pattern.compile("^\\w+$").matcher(s[0]).matches()) {
            return "";
        }

        return s[0] + " " + (s[1].equals("1") ? "asc" : "desc");
    }

    private Map getSqlparts(Map dataset) {
        try {
            Object sqlpart = ((Map) dataset.get("sqlparts")).get("sqlpart");
            Map sqlparts = new HashMap();
            if (sqlpart instanceof ArrayList) {
                for (Object part : (ArrayList) sqlpart) {
                    sqlparts.put(((Map) part).get("part"), part);
                }
            } else {
                sqlparts.put(((Map) sqlpart).get("part"), sqlpart);
            }
            return sqlparts;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 替换sql中的$$中间的用户参数: area_id = '$user.area_id%'
     * 从登录用户参数中获取user.area_id
     */
    protected String dealUserArgs(String sql, Map args) {
        if (StringUtils.isBlank(sql)) {
            return "";
        }
        String user = (String) args.get(Constant.User.CURRENT_USER);
        //todo
        Object sysUser = JSONObject.parseObject(user, Object.class);

        String[] s = sql.split("\\@");
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < s.length; i++) {
            if (i % 2 == 0) {
                sb.append(s[i]);
            } else {
                // 读取user属性 s[i]
                String arg = "";
                try {
                    arg = BeanUtils.getProperty(sysUser, s[i]);
                } catch (Exception e) {
                    return "";
                }
                sb.append(arg);
            }
        }
        return sb.toString();
    }

    /**
     * 替换sql中的缓存参数: period = #infPeriod.periodId#
     * 从缓存获取变量uinfPeriod.periodId
     */
    protected String dealCache(String sql) {
        if (StringUtils.isBlank(sql)) {
            return "";
        }
        String[] s = sql.split("\\#");
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < s.length; i++) {
            if (i % 2 == 0) {
                sb.append(s[i]);
            } else {
                String value = "";
                String[] s2 = s[i].split("\\.");
                // 动态调用服务获取String
                Object callee = Platform.getInstance().getBean(s2[0]);
                if (callee != null) {
                    try {
                        value = (String) MethodUtils.invokeMethod(callee, s2[1], null);//todo 加参数
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                sb.append(value);
            }
        }
        return sb.toString();
    }

    //每页条数
    protected int getPageSize(Map dataset, Map args) {
        // 是否配置了参数名pageSizeArg，如果没有默认用pageSize
        String pageSizeArg = (String) dataset.get("pageSizeArg");
        if (pageSizeArg == null) {
            pageSizeArg = "pageSize";
        }
        // 从参数获取
        Object argPageSize = args.get(pageSizeArg);
        if (argPageSize != null) {
            try {
                return Integer.parseInt(argPageSize.toString());
            } catch (Exception e) {
            }
        }
        //如果没有使用配置的值
        Integer configPageSize = (Integer) dataset.get("pageSize");
        //如果没有配置值使用缺省值
        if (configPageSize != null) {
            return configPageSize;
        }
        return Pagination.DEFAULT_PAGE_SIZE;
    }

    //第几页
    protected int getPageNo(Map dataset, Map args) {
        //根据pageNoArg从参数args中获取，没有默认1。
        try {
            Object oPageNoArg = dataset.get("pageNoArg");
            if (oPageNoArg == null) {
                oPageNoArg = "pageNo";
            }
            String sPageNo = (String) args.get(oPageNoArg.toString());
            return Integer.parseInt(sPageNo);
        } catch (Exception e) {
        }
        return 1;
    }

    /**
     * 处理查询条件，替换参数。要求Vars中的参数要有顺序
     */
    protected String dealKeyword(String sql, Map dataset, Map args) {
        List<Map> vars = getVars(dataset);
        if (vars == null || vars.size() == 0) {
            return sql;
        }
        String[] searchList = new String[vars.size()];
        String[] replacementList = new String[vars.size()];

        int i = 0;
        for (Map var : vars) {
            String argValue = (String) args.get(var.get("argName"));
            replacementList[i] = argValue;

            //参数最多支持99个
            if (i < 9) {
                searchList[i] = "?0" + (i + 1);
            } else {
                searchList[i] = "?" + (i + 1);
            }
            i++;
        }

        String result = StringUtils.replaceEach(sql, searchList, replacementList);

        return result;
    }

    protected List getVars(Map dataset) {
        try {
            Object var = ((Map) dataset.get("vars")).get("var");
            List vars = new ArrayList();
            if (var instanceof ArrayList) {
                vars = (ArrayList) var;
            } else {
                vars.add((Map) var);
            }
            return vars;
        } catch (Exception e) {
            return null;
        }
    }

    protected List getTranscodes(Map dataset) {
        try {
            Object transcode = ((Map) dataset.get("transcodes")).get("transcode");
            List transcodes = new ArrayList();
            if (transcode instanceof ArrayList) {
                transcodes = (ArrayList) transcode;
            } else {
                transcodes.add((Map) transcode);
            }
            return transcodes;
        } catch (Exception e) {
            return null;
        }
    }

    //单条数据转码
    protected void transcodeMap(List<Map> transcodes, Map<String, Object> record) {
        for (Map transcode : transcodes) {
            Object codeColumn = record.get(transcode.get("code").toString());
            if (codeColumn == null) {
                continue;
            }
            String totransCode = codeColumn.toString();
            if (StringUtils.isBlank(totransCode)) {
                continue;
            }
            String transedCode = "";
            switch ((Integer) transcode.get("type")) {
                case 1:
                    transedCode = Platform.getInstance().getDicValue(transcode.get("transcode").toString(), totransCode);
                    break;
                case 2:
                    transedCode = transcodeInDB(transcode.get("transcode").toString(), record);
                    break;
                case 3:
                    transedCode = StringEscapeUtils.escapeHtml(totransCode); // 2016-2-22
                    break;
                case 4:
                    transedCode = StringEscapeUtils.escapeJava(totransCode); // 2019-1-17
            }
            // 更新record
            record.put(transcode.get("code").toString(), transedCode);
        }
    }

    //列表数据转码
    protected void transcodeList(List<Map> transcodes, List<Map<String, Object>> data) {
        for (Map<String, Object> record : data) {
            transcodeMap(transcodes, record);
        }
    }

    /**
     * 根据一个或多个参数，从数据库查找，返回一个String数据，例如：<br>
     * select name from table where colum1=$code1$ and column2=$code2$ <br>
     * select count(*) from table where colum1=$code1$ and column2=$code2$ <br>
     * 其中，code1、code2是record map的key
     */
    private String transcodeInDB(String transcode, Map record) {
        if (StringUtils.isBlank(transcode)) {
            return "";
        }
        String[] s = transcode.split("\\$");
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < s.length; i++) {
            if (i % 2 == 0) {
                sb.append(s[i]);
            } else {
                Object obj = record.get(s[i]);
                if (obj == null) {
                    return "";
                }
                sb.append(obj);
            }
        }
        String sql = sb.toString();
        Map<String, Object> resultMap = jdbcTemplate.queryForMap(sql);

        String result = "";
        for (Map.Entry<String, Object> entry : resultMap.entrySet()) {
            Object o = entry.getValue();
            result = o.toString();
        }
        return result;
    }
}
